﻿// --------------------------------------------------------------------------------------------------------------------
// <summary>
//   read/write registry keys to override syswow behavior.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Wolfpack.Contrib.Checks.RegistryAlarms
{
    using System;
    using System.Collections.Generic;
    using Wolfpack.Core;
    using Microsoft.Win32;

    /// <summary>
    /// read/write registry keys
    /// </summary>
    public static class RegistryKeyExtension
    {
        #region Public Methods

        /// <summary>
        /// To read a registry registryKey value. Catch a null reference exception in calling code.
        /// </summary>
        /// <param name="registryKey">
        /// The RegistryKey to extend.
        /// </param>
        /// <param name="keyName">
        /// The registry registryKey name.
        /// </param>
        /// <param name="subKeyString">
        /// The sub registryKey string.
        /// </param>
        /// <returns>
        /// The value of the registry registryKey. Will return null if nothing is found.
        /// </returns>
        public static object GetValue64(this RegistryKey registryKey, string subKeyString, string keyName)
        {   
            object value = null;

            using (RegistryKey registry64 = RegistryKey.FromHandle(registryKey.Handle, RegistryView.Registry64))
            {   
                try
                {
                    RegistryKey subKey = registry64.OpenSubKey(subKeyString, true);

                    if (subKey != null)
                    {
                        value = subKey.GetValue(keyName);
                    }

                    CloseDispose(new List<RegistryKey> { registry64, subKey });
                }
                catch (Exception ex) 
                {
                    Logger.Debug("Error during registry read {0}, {1}. Exception: {2}", subKeyString, keyName, ex.Message);
                }
            }

            return value;
        }

        /// <summary>
        /// To delete a registry value.
        /// </summary>
        /// <param name="registryKey">
        /// The RegistryKey to extend.
        /// </param>
        /// <param name="keyName">
        /// The registryKey name to delete. By default under HKLM\Software\Microsoft\PKI. Set SubKey to change default. 
        /// </param>
        /// <param name="subKeyString">
        /// The subkey string.
        /// </param>
        public static void DeleteValue64(
            this RegistryKey registryKey, string subKeyString, string keyName)
        {
            using (RegistryKey registry64 = RegistryKey.FromHandle(registryKey.Handle, RegistryView.Registry64))
            {
                try
                {
                    RegistryKey subKey = registry64.OpenSubKey(subKeyString, true);

                    if (subKey != null)
                    {
                        subKey.DeleteValue(keyName);
                    }

                    CloseDispose(new List<RegistryKey> { registry64, subKey });
                }
                catch (Exception ex)
                {
                    Logger.Debug("Error trying to delete registry: {0} {1}. Exception: {2}", subKeyString, keyName, ex.Message);
                }
            }
        }

        /// <summary>
        /// Write a registry value.
        /// </summary>
        /// <param name="registryKey">
        /// The RegistryKey to extend.
        /// </param>
        /// <param name="keyName">
        /// The registry name to write to.
        /// </param>
        /// <param name="value">
        /// The registry value to write.
        /// </param>
        /// <param name="subKeyString">
        /// The subkey after HKLM.  
        /// </param>
        /// <param name="valueKind">
        /// The type of registry value.
        /// </param>
        public static void SetValue64(
            this RegistryKey registryKey,
            string subKeyString,
            string keyName,
            object value,
            RegistryValueKind valueKind = RegistryValueKind.String)
        {
            using (RegistryKey registry64 = RegistryKey.FromHandle(registryKey.Handle, RegistryView.Registry64))
            {
                try
                {
                    RegistryKey subKey = registry64.CreateSubKey(subKeyString);
                    if (subKey != null)
                    {
                        subKey.DeleteValue(keyName);
                        subKey.OpenSubKey(subKeyString, true);
                        subKey.SetValue(keyName, value, valueKind);
                    }

                    CloseDispose(new List<RegistryKey> { registry64, subKey });
                }
                catch (Exception ex)
                {
                    Logger.Debug("Error deleting registry {0} {1}. Exception: {2}", subKeyString, keyName, ex.Message);
                }
            }
        }

        /// <summary>
        /// The delete value 64.
        /// </summary>
        /// <param name="registryKey">
        /// The registry key.
        /// </param>
        /// <param name="subKeyString">
        /// The sub key string.
        /// </param>
        public static void DeleteSubKeyTree64(this RegistryKey registryKey, string subKeyString)
        {
            using (RegistryKey registry64 = RegistryKey.FromHandle(registryKey.Handle, RegistryView.Registry64))
            {
                try
                {
                    RegistryKey subKey = registry64.CreateSubKey(subKeyString);
                    if (subKey != null)
                    {
                        registry64.DeleteSubKeyTree(subKeyString);
                        subKey.Close();
                    }

                    CloseDispose(new List<RegistryKey> { registry64, subKey });

                }
                catch (Exception ex)
                {
                    Logger.Debug("Error Deleting Registry. Exception: {0}", ex.Message);
                }
            }
        }

        /// <summary>
        /// The delete value 64.
        /// </summary>
        /// <param name="registryKey">
        /// The registry key.
        /// </param>
        /// <param name="subKeyString">
        /// The sub key string.
        /// </param>
        /// <returns>
        /// The <see cref="string"/>.
        /// </returns>
        public static string[] GetSubKeyNames64(this RegistryKey registryKey, string subKeyString)
        {
            using (RegistryKey registry64 = RegistryKey.FromHandle(registryKey.Handle, RegistryView.Registry64))
            {
                RegistryKey subKey = registry64.OpenSubKey(subKeyString);
                string[] subKeys = subKey.GetSubKeyNames();
                CloseDispose(new List<RegistryKey> { subKey });

                if (subKeys.Length > 0)
                {
                    return subKeys;
                }

                Logger.Debug("Subkey does not exist {0}.", subKeyString);
                return null;
            }
        }

        /// <summary>
        /// The close dispose.
        /// </summary>
        /// <param name="registryKeys">
        /// The registry Keys.
        /// </param>
        public static void CloseDispose(List<RegistryKey> registryKeys)
        {
            foreach (var registryKey in registryKeys)
            {
                if (registryKey != null)
                {
                    registryKey.Close();
                    registryKey.Dispose();
                }
            }
        }

        /// <summary>
        /// The close dispose.
        /// </summary>
        /// <param name="registryKey">
        /// The registry key.
        /// </param>
        public static void CloseDispose(this RegistryKey registryKey)
        {
            registryKey.Close();
            registryKey.Dispose();
        }

        #endregion
    }
}